﻿//-----------------------------------------------------------------------------
// <copyright company="Cortego AB, 2010" file="Program.cs">
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
// </copyright>
//-----------------------------------------------------------------------------
namespace Cortego.ADFS.FIMAttributeStore.Tests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Cortego.ADFS.FIMAttributeStore;

    /// <summary>
    /// Test client utility for testing Cortego.FIMAttributeStore.
    /// </summary>
    public class Program
    {
        /// <summary>
        /// Program Main method.
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        public static void Main(string[] args)
        {
            Console.Clear();
            Console.BackgroundColor = ConsoleColor.Black;
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("Cortego ADFS FIMAttributeStore Test client.\n\n");
            Console.ResetColor();

            try
            {
                if (args.Length == 0)
                {
                    // Run default tests and show usage.
                    TestAttributeStoreForPerson();
                    TestAttributeStoreForGroup();
                    TestAttributeStoreForMultiValue();
                    WriteUsage();
                }
                else if (args.Length == 1)
                {
                    // Show usage.
                    if (args[0] == "/?")
                    {
                        WriteUsage();
                    }
                }
                else if (args.Length == 2)
                {
                    // Run custom query with default attributes ("DisplayName,ObjectID").
                    if (args[0].ToLower() == "/q")
                    {
                        TestAttributeStoreCustomQuery(args[1], null);
                    }
                }
                else if (args.Length == 4)
                {
                    // Run custom query with attributes specified.
                    if (args[0].ToLower() == "/q" && args[2].ToLower() == "/a")
                    {
                        TestAttributeStoreCustomQuery(args[1], args[3]);
                    }
                }
            }
            catch (Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write("Exception Occured!\n\n");
                Console.Write(e.Message + "\n\n" + e.StackTrace);
                Console.ResetColor();
            }

            Console.ReadKey();
        }

        /// <summary>
        /// Gets configuration from App.config and prepares it for use with FIMAttributeStore.
        /// </summary>
        /// <returns>Configuration settings as Dictionary.</returns>
        private static Dictionary<string, string> Config()
        {
            // Set configuration settings.
            Dictionary<string, string> config = new Dictionary<string, string>();
            config.Add("Endpoint", Properties.Settings.Default.Endpoint);
            config.Add("UserName", Properties.Settings.Default.UserName);
            config.Add("UserDomain", Properties.Settings.Default.UserDomain);
            config.Add("Password", Properties.Settings.Default.Password);
            config.Add("TracingEnabled", Properties.Settings.Default.TracingEnabled);
            config.Add("FIMServiceSPN", Properties.Settings.Default.FIMServiceSPN);

            return config;
        }

        /// <summary>
        /// Writes usage information to Console.
        /// </summary>
        private static void WriteUsage()
        {
            Console.ForegroundColor = ConsoleColor.White;
            Console.Write("Allows for testing of queries and connectivity against FIM.\n\n");
            Console.Write("Cortego.ADFS.FIMAttributeStore.Tests.exe /Q query [/A] attributes\n\n");
            Console.Write("/Q query      The query to execute\n");
            Console.Write("/A attributes      The attributes to return from FIM (optional)\n\n");
            Console.Write("Note:Connection parameters are edited in the application config file.\n\n");
            Console.Write("Usage:\nCortego.ADFS.FIMAttributeStore.Tests.exe /Q query /A attributes\n\n");
            Console.Write("Examples:\n");
            Console.Write("Cortego.ADFS.FIMAttributeStore.Tests.exe /Q \"/Person[ObjectID='fb89aefa-5ea1-47f1-8890-abe7797d6497']\" /A \"DisplayName,ObjectID\" \n");
            Console.Write("Cortego.ADFS.FIMAttributeStore.Tests.exe /Q \"/Group[ComputedMember = /Person[ObjectID='fb89aefa-5ea1-47f1-8890-abe7797d6497']]\" /A \"DisplayName\" \n");
            Console.Write("Cortego.ADFS.FIMAttributeStore.Tests.exe /Q \"/Set[ComputedMember = /Person[DisplayName='John Doe']]\" /A \"DisplayName\" \n");
            Console.Write("Cortego.ADFS.FIMAttributeStore.Tests.exe /Q \"/SearchScopeConfiguration[ObjectID='2d66d066-47ed-4736-bce1-b840eb7156d4']\" /A \"DisplayName,UsageKeyword\" \n");
            Console.ResetColor();
        }

        /// <summary>
        /// Runs test using FIMAttributeStore for getting a Person resource from FIM (Built-in Synchronization Account).
        /// </summary>
        /// <param name="query">XPath query against FIM.</param>
        /// <param name="attributes">Attributes to return from FIM.</param>
        private static void TestAttributeStoreCustomQuery(string query, string attributes)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Custom Query: \"{0};{1}\"", query, attributes);
            Console.ResetColor();

             // Create attribute store.
            FIMAttributeStore attributeStore = new FIMAttributeStore();

            attributeStore.Initialize(Config());

            // Default attributes (unless specified).
            if (string.IsNullOrEmpty(attributes))
            {
                attributes = "DisplayName, ObjectID";
            }

            // Specify attributes and execute query.
            string[] columns = attributes.Split(new char[] { ',' });
            IAsyncResult result = attributeStore.BeginExecuteQuery("{0};{1}", new string[] { query, attributes }, null, null);

            // Get and display returned data.
            string[][] data = attributeStore.EndExecuteQuery(result);
            WriteResults(columns, data);
        }

        /// <summary>
        /// Runs test using FIMAttributeStore for getting a Person resource from FIM (Built-in Synchronization Account).
        /// </summary>
        private static void TestAttributeStoreForPerson()
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Person with ObjectID=fb89aefa-5ea1-47f1-8890-abe7797d6497 (Built-in Synchronization Account):");
            Console.ResetColor();

            // Create attribute store.
            FIMAttributeStore attributeStore = new FIMAttributeStore();
            
            attributeStore.Initialize(Config());
            
            // Specify attributes and execute query.
            string[] columns = new string[] { "ObjectID", "DisplayName", "FirstName", "LastName", "AccountName", "JobTitle" };
            IAsyncResult result = attributeStore.BeginExecuteQuery("/Person[ObjectID='{0}'];" + string.Join(",", columns), new string[] { "fb89aefa-5ea1-47f1-8890-abe7797d6497" }, null, null);

            // Get and display returned data.
            string[][] data = attributeStore.EndExecuteQuery(result);
            WriteResults(columns, data);
        }

        /// <summary>
        /// Runs test using FIMAttributeStore for getting Set resources from FIM for Built-in Synchronization Account.
        /// </summary>
        private static void TestAttributeStoreForGroup()
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Sets for person with ObjectID=fb89aefa-5ea1-47f1-8890-abe7797d6497 (Built-in Synchronization Account):");
            Console.ResetColor();

            // Create attribute store.
            FIMAttributeStore attributeStore = new FIMAttributeStore();
            
            // Set configuration settings.
            attributeStore.Initialize(Config());

            // Specify attributes and execute query.
            string[] columns = new string[] { "DisplayName" };
            IAsyncResult result = attributeStore.BeginExecuteQuery("/Set[ComputedMember = /Person[ObjectID='{0}']];" + string.Join(",", columns), new string[] { "fb89aefa-5ea1-47f1-8890-abe7797d6497" }, null, null);

            // Get and display returned data.
            string[][] data = attributeStore.EndExecuteQuery(result);
            WriteResults(columns, data);
        }

        /// <summary>
        /// Runs test using FIMAttributeStore for getting a Search Scope resource from FIM 
        /// for displaying the posibility to return single-valued and multi-valued attributes in the same query.
        /// </summary>
        private static void TestAttributeStoreForMultiValue()
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("UsageKeywords of SearchScope with ObjectID=2d66d066-47ed-4736-bce1-b840eb7156d4 (All Users):");
            Console.ResetColor();

            // Create attribute store.
            FIMAttributeStore attributeStore = new FIMAttributeStore();

            // Set configuration settings.
            attributeStore.Initialize(Config());

            // Specify attributes and execute query.
            string[] columns = new string[] { "DisplayName", "UsageKeyword" };
            IAsyncResult result = attributeStore.BeginExecuteQuery("/SearchScopeConfiguration[ObjectID='{0}'];" + string.Join(",", columns), new string[] { "2d66d066-47ed-4736-bce1-b840eb7156d4" }, null, null);

            // Get and display returned data.
            string[][] data = attributeStore.EndExecuteQuery(result);
            WriteResults(columns, data);
        }

        /// <summary>
        /// Displays results from FIMAttributeStore.
        /// </summary>
        /// <param name="columnNames">Column names (Claims) used in query against FIM with FIMAttributeStore.</param>
        /// <param name="rows">Rows of information retrieved from FIMAttributeStore.</param>
        private static void WriteResults(string[] columnNames, string[][] rows)
        {
            foreach (string columnName in columnNames)
            {
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Write("[");
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write(string.Format("{0}", columnName));
                Console.ForegroundColor = ConsoleColor.Magenta;
                Console.Write("]");
            }

            Console.ResetColor();
            Console.Write("\n");

            List<List<string>> rowList =
                rows
                    .Select(detail => detail.ToList())
                    .ToList();

            foreach (List<string> row in rowList)
            {
                for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++)
                {
                    if (!string.IsNullOrEmpty(row[columnIndex]))
                    {
                        Console.ForegroundColor = ConsoleColor.Magenta;
                        Console.Write("[");
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.Write("{1}", columnNames[columnIndex], row[columnIndex]);
                        Console.ForegroundColor = ConsoleColor.Magenta;
                        Console.Write("]");
                        Console.ResetColor();
                    }
                    else
                    {
                        Console.ForegroundColor = ConsoleColor.Magenta;
                        Console.Write("[");
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write("null");
                        Console.ForegroundColor = ConsoleColor.Magenta;
                        Console.Write("]");
                        Console.ResetColor();
                    }

                    if (columnIndex == columnNames.Length - 1)
                    {
                        Console.Write("\n");
                    }
                }
            }

            Console.WriteLine();
        }
    }
}